home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Info-Mac 4
/
Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso
/
Development
/
General
/
DR1.#1 PowerPlant ƒ
/
LView.cp
< prev
next >
Wrap
Text File
|
1994-02-10
|
35KB
|
1,398 lines
// ===========================================================================
// LView.cp ©1993 Metrowerks Inc. All rights reserved.
// ===========================================================================
//
// Abstract class for a Pane which can be larger than its Frame (i.e., it
// can scroll) and can have SubPanes
#include "LView.h"
#include "LList.h"
#include "LListIterator.h"
#include "LStream.h"
// === Local Constants ===
const Int16 max_PortOrigin = 16384;
const Int16 min_PortOrigin = -32768;
const Int32 mask_Lo14Bits = 0x00003FFF;
// === Class Variables ===
LView* LView::sInFocusView = nil;
// ---------------------------------------------------------------------------
// • LView()
// ---------------------------------------------------------------------------
// Default Constructor
LView::LView()
{
InitView(); // Initialize to default values
}
// ---------------------------------------------------------------------------
// • LView(const LView&)
// ---------------------------------------------------------------------------
// Copy Constructor
//
// Does shallow copy; SubPanes are not copied.
LView::LView(
const LView &inOriginal)
: LPane(inOriginal)
{
InitView(); // Initialize to default values
// Copy members of Original. There's no need to copy mRevealedRect
// and mUpdateRgnH because they'll be computed when this View
// is put inside its SuperView.
mImageSize = inOriginal.mImageSize;
mImageLocation = inOriginal.mImageLocation;
mScrollUnit = inOriginal.mScrollUnit;
mPortOrigin = inOriginal.mPortOrigin;
mReconcileOverhang = inOriginal.mReconcileOverhang;
}
// ---------------------------------------------------------------------------
// • LView(LStream*)
// ---------------------------------------------------------------------------
// Construct View from data in a Stream
LView::LView(
LStream *inStream)
: LPane(inStream)
{
DataIDT dataID;
inStream->ReadData(&dataID, sizeof(DataIDT));
SignalIf_(dataID != 'View');
InitView(); // Initialize to default values
SViewInfo viewInfo;
inStream->ReadData(&viewInfo, sizeof(SViewInfo));
mImageSize = viewInfo.imageSize;
mScrollUnit = viewInfo.scrollUnit;
mReconcileOverhang = viewInfo.reconcileOverhang;
ScrollImageTo(viewInfo.scrollPos.h, viewInfo.scrollPos.v, false);
CalcRevealedRect();
SetDefaultView(this);
}
// ---------------------------------------------------------------------------
// • InitView
// ---------------------------------------------------------------------------
// Initialize View member variables to default values
void
LView::InitView()
{
mImageSize.width = mFrameSize.width;
mImageSize.height = mFrameSize.height;
mImageLocation.h = mImageLocation.v = 0;
mScrollUnit.h = mScrollUnit.v = 1;
mPortOrigin.h = mPortOrigin.v = 0;
mRevealedRect.left =
mRevealedRect.top =
mRevealedRect.right =
mRevealedRect.bottom = 0;
mUpdateRgnH = NewRgn();
mReconcileOverhang = false;
}
// ---------------------------------------------------------------------------
// • ~LView
// ---------------------------------------------------------------------------
// Destructor
//
LView::~LView()
{
DeleteAllSubPanes(); // Delete Panes contained by this View
DisposeRgn(mUpdateRgnH);
OutOfFocus(this); // Don't leave a dangling Focus
if (sDefaultView == this) {
SetDefaultView(nil);
}
}
// ---------------------------------------------------------------------------
// • FinishCreate
// ---------------------------------------------------------------------------
// Wrapper function for FinishCreateSelf
// You will rarely want to override this function
//
// SubPanes are told to FinishCreateSelf *before* their SuperView.
// Therefore, a SupverView is assured that all its SubPanes have
// finished creating when its FinishCreateSelf function gets called.
void
LView::FinishCreate()
{
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->FinishCreate();
}
FinishCreateSelf();
}
void
LView::AddSubPane(
LPane *inSub)
{
SignalIf_(inSub == nil);
mSubPanes.InsertItemsAt(1, index_Last, inSub);
OrientSubPane(inSub);
}
void
LView::RemoveSubPane(
LPane *inSub)
{
SignalIf_(inSub == nil);
mSubPanes.Remove(inSub);
}
void
LView::DeleteAllSubPanes()
{
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
mSubPanes.Remove(theSub);
delete theSub;
}
}
void
LView::OrientSubPane(
LPane *inSub)
{
if (mEnabled == triState_On) {
inSub->SuperEnable();
} else {
inSub->SuperDisable();
}
if (mActive == triState_On) {
inSub->SuperActivate();
} else {
inSub->SuperDeactivate();
}
if (mVisible == triState_On) {
inSub->SuperShow();
} else {
inSub->SuperHide();
}
}
LList&
LView::GetSubPanes()
{
return mSubPanes;
}
void
LView::GetImageSize(
SDimension32 &outSize) // +++ possible inline
{
outSize = mImageSize;
}
void
LView::GetImageLocation(
SPoint32 &outLocation) // +++ possible inline
{
outLocation = mImageLocation;
}
void
LView::GetScrollPosition(
SPoint32 &outScrollPosition)
{
outScrollPosition.h = mFrameLocation.h - mImageLocation.h;
outScrollPosition.v = mFrameLocation.v - mImageLocation.v;
}
void
LView::GetRevealedRect(
Rect &outRect) // +++ possible inline
{
outRect = mRevealedRect;
}
// ---------------------------------------------------------------------------
// • CalcRevealedRect
// ---------------------------------------------------------------------------
// Calculate the portion of the Frame which is revealed through the
// Frames of all SuperViews. RevealedRect is in Port coordinates.
void
LView::CalcRevealedRect()
{
// Start with the Frame
if (CalcPortFrameRect(mRevealedRect)) {
// Frame is in QD Space
if (mSuperView != nil) { // Intersect Frame with RevealedRect
// of SuperView
Rect superRevealed;
mSuperView->GetRevealedRect(superRevealed);
SectRect(&superRevealed, &mRevealedRect, &mRevealedRect);
}
} else { // Frame not in QD Space
mRevealedRect.left = // so RevealedRect is empty
mRevealedRect.top =
mRevealedRect.right =
mRevealedRect.bottom = 0;
}
}
// ---------------------------------------------------------------------------
// • CalcPortOrigin
// ---------------------------------------------------------------------------
// Calculate the coordinate origin for the Port needed to set up the
// Local coordinates of a View
//
// The Port origin must be in 16-bit space. In fact, the limitation is more
// restrictive because the entire Port must be in 16-bit space. The origin
// is the top left corner. To make sure that the bottom right corner is
// in 16-bit space, we force the origin to be less than 2^14 (16,384),
// which allows Port dimensions of a maximum of 16,384 pixels. At 72 dpi,
// this is about 227 inches or 19 feet (much more screen or printer area
// than you can get with current technology).
//
// This means that Local and Image coordinates will be the same when the
// Image size is less than 16,384 pixels. For Images greater than this,
// you can't use absolute coordinates for drawing. You need to offset
// the coordinates using ImageToLocalPt() and LocalToImagePt().
//
// The true coordinates offset is the distance between the top left corners
// of the Image and the Port. If this offset is greater than 2^14, we
// use an effective offset that is the true offset modulo 2^14:
// effective_offset = true_offset modulo 2^14
// Using this effective offset maintains the bit-wise alignment of the Port
// with respect to base-2 byte boundaries. This is important for drawing
// Toolbox Patterns and PixPats, as well as for CopyBits calls.
void
LView::CalcPortOrigin()
{
Int32 coord = -mImageLocation.h;
if (coord > max_PortOrigin) { // coord is too big
coord &= mask_Lo14Bits; // use coord modulo 2^14
} else if (coord < min_PortOrigin) {
coord = min_PortOrigin; // coord is too small, limit to minimum
}
mPortOrigin.h = coord;
coord = -mImageLocation.v;
if (coord > max_PortOrigin) {
coord &= mask_Lo14Bits;
} else if (coord < min_PortOrigin) {
coord = min_PortOrigin;
}
mPortOrigin.v = coord;
}
RgnHandle
LView::GetLocalUpdateRgn()
{
// Copy update region, which is in port
// coordinates
RgnHandle localUpdateRgnH = NewRgn();
CopyRgn(mUpdateRgnH, localUpdateRgnH);
// Offset copy into local coordinates
Point localOffset = {0, 0};
PortToLocalPoint(localOffset);
OffsetRgn(localUpdateRgnH, localOffset.h, localOffset.v);
return localUpdateRgnH; // Return copy, caller must dispose it
}
RgnHandle
LView::GetUpdateRgn()
{
return mUpdateRgnH;
}
void
LView::SetReconcileOverhang(
Boolean inSetting)
{
mReconcileOverhang = inSetting;
}
// ---------------------------------------------------------------------------
// • ResizeFrameBy
// ---------------------------------------------------------------------------
// Change the Frame size by the specified amounts
//
// inWidthDelta and inHeightDelta specify, in pixels, how much larger
// to make the Frame. Positive deltas increase the size, negative deltas
// reduce the size.
void
LView::ResizeFrameBy(
Int16 inWidthDelta,
Int16 inHeightDelta,
Boolean inRefresh)
{
LPane::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
CalcRevealedRect();
OutOfFocus(this);
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->AdaptToSuperFrameSize(inWidthDelta, inHeightDelta, inRefresh);
}
ReconcileFrameAndImage(inRefresh);
}
// ---------------------------------------------------------------------------
// • MoveBy
// ---------------------------------------------------------------------------
// Move the location of the Image and Frame by the specified amounts
//
// inHorizDelta and inVertDelta specify, in pixels, how far to move the
// Frame (within its surrounding Image). Positive horiz deltas move to
// the left, negative to the right. Positive vert deltas move down,
// negative up.
void
LView::MoveBy(
Int32 inHorizDelta,
Int32 inVertDelta,
Boolean inRefresh)
{
if (inRefresh) {
Refresh();
}
mImageLocation.h += inHorizDelta;
mImageLocation.v += inVertDelta;
mFrameLocation.h += inHorizDelta;
mFrameLocation.v += inVertDelta;
CalcPortOrigin();
CalcRevealedRect();
OutOfFocus(this);
if (inRefresh) {
Refresh();
}
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->MoveBy(inHorizDelta, inVertDelta, false);
}
}
void
LView::SavePlace(
LStream *outPlace)
{
LPane::SavePlace(outPlace);
outPlace->WriteData(&mImageLocation, sizeof(SPoint32));
}
void
LView::RestorePlace(
LStream *inPlace)
{
LPane::RestorePlace(inPlace);
inPlace->ReadData(&mImageLocation, sizeof(SDimension32));
CalcPortOrigin();
CalcRevealedRect();
}
void
LView::AdaptToNewSurroundings()
{
CalcRevealedRect();
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->AdaptToNewSurroundings();
}
}
// ---------------------------------------------------------------------------
// • AdaptToSuperFrameSize
// ---------------------------------------------------------------------------
// Adjust state of View when size of SuperView's Frame changes by the
// specified amounts
void
LView::AdaptToSuperFrameSize(
Int32 inSurrWidthDelta, // Change in width of SuperView
Int32 inSurrHeightDelta, // Change in height of SuperView
Boolean inRefresh)
{
LPane::AdaptToSuperFrameSize(inSurrWidthDelta, inSurrHeightDelta,
inRefresh);
AdaptToNewSurroundings();
}
void
LView::Show()
{
LPane::Show();
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->SuperShow();
}
}
void
LView::SuperShow()
{
LPane::SuperShow();
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->SuperShow();
}
}
void
LView::Hide()
{
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->SuperHide();
}
LPane::Hide();
}
void
LView::SuperHide()
{
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->SuperHide();
}
LPane::SuperHide();
}
void
LView::Activate()
{
LPane::Activate();
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->SuperActivate();
}
}
void
LView::SuperActivate()
{
LPane::SuperActivate();
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->SuperActivate();
}
}
void
LView::Deactivate()
{
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->SuperDeactivate();
}
LPane::Deactivate();
}
void
LView::SuperDeactivate()
{
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->SuperDeactivate();
}
LPane::SuperDeactivate();
}
void
LView::Enable()
{
LPane::Enable();
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->SuperEnable();
}
}
void
LView::SuperEnable()
{
LPane::SuperEnable();
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->SuperEnable();
}
}
void
LView::Disable()
{
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->SuperDisable();
}
LPane::Disable();
}
void
LView::SuperDisable()
{
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->SuperDisable();
}
LPane::SuperDisable();
}
void
LView::EstablishPort()
{
if (mSuperView != nil) {
mSuperView->EstablishPort();
}
}
// ---------------------------------------------------------------------------
// • FocusDraw
// ---------------------------------------------------------------------------
// Prepare for drawing in the View by setting the Port and clipping area
//
// Returns true if the View is focused
// Returns false if the View could not be focused
// This happens when no part of the View is revealed (which means
// that the clipping area would be empty) or if drawing is locked.
//
// If FocusDraw returns true, it also means that the View's Frame is
// in QuickDraw space. The Revealed area would be empty if the Frame
// did not intersect the Port rectangle (which is always in QuickDraw
// space) of the Mac Port containing the View.
Boolean
LView::FocusDraw()
{
Boolean focused = (mLockLevel >= 0);
// Skip if already in focus or
// drawing is locked
if ( (this != sInFocusView) && focused ) {
focused = false;
// Don't focus if no part of View
// Frame is revealed
if (mRevealedRect.left < mRevealedRect.right) {
EstablishPort(); // Set current Mac Port
// Set up local coordinate system
SetOrigin(mPortOrigin.h, mPortOrigin.v);
// Clip to revealed area of View
Rect clippingRect = mRevealedRect;
PortToLocalPoint(topLeft(clippingRect));
PortToLocalPoint(botRight(clippingRect));
ClipRect(&clippingRect);
sInFocusView = this; // Cache current Focus
focused = true;
}
}
return focused;
}
// ---------------------------------------------------------------------------
// • OutOfFocus [static]
// ---------------------------------------------------------------------------
// Notify View system that a View is no longer in focus
//
// Call when the coordinate system or clipping region of a View changes,
// passing a pointer to that View. This clears the saved focus if that
// View was the one in focus.
//
// Use nil for inView if you manually change (and don't restore) the
// current port or clipping region
void
LView::OutOfFocus(
LView *inView)
{
if ( (inView == nil) || (sInFocusView == inView) ) {
sInFocusView = nil;
}
}
// ---------------------------------------------------------------------------
// • Draw
// ---------------------------------------------------------------------------
// Draw a View and all its SubPanes
//
// inSuperDrawRgnH specifies, in Port coordinates, the portion of the
// View's SuperView that needs to be drawn. Specify nil to draw the
// entire View.
void
LView::Draw(
RgnHandle inSuperDrawRgnH)
{
// Don't draw if invisible or unable
// to put in focus
if (IsVisible() && FocusDraw()) {
// Area of this View to draw is the
// intersection of inSuperDrawRgnH
// with the Revealed area of this View
RectRgn(mUpdateRgnH, &mRevealedRect);
if (inSuperDrawRgnH != nil) {
SectRgn(inSuperDrawRgnH, mUpdateRgnH, mUpdateRgnH);
}
if (!EmptyRgn(mUpdateRgnH)) {
// Some portion needs to be drawn
DrawSelf(); // A View is visually behind its
// SubPanes so it draws itself first,
// then its SubPanes
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->Draw(mUpdateRgnH);
}
}
SetEmptyRgn(mUpdateRgnH); // Emptying update region frees up memory
// if this region wasn't rectangular
}
}
// ---------------------------------------------------------------------------
// • CountPanels
// ---------------------------------------------------------------------------
// Return the number of horizontal and vertical Panels. A Panel is a
// "frameful" of a View's Image.
void
LView::CountPanels(
Uint32 &outHorizPanels,
Uint32 &outVertPanels)
{
SDimension32 imageSize;
GetImageSize(imageSize);
SDimension16 frameSize;
GetFrameSize(frameSize);
outHorizPanels = 1;
if (frameSize.width > 0 && imageSize.width > 0) {
outHorizPanels = ((imageSize.width - 1) / frameSize.width) + 1;
}
outVertPanels = 1;
if (frameSize.height > 0 && imageSize.height > 0) {
outVertPanels = ((imageSize.height - 1) / frameSize.height) + 1;
}
}
// ---------------------------------------------------------------------------
// • PrintPanel
// ---------------------------------------------------------------------------
// Try to Print a Panel of a View
//
// The View is at the top level of the Printout, meaning that it controls
// pagination. This functions scrolls the View to the specified panel.
void
LView::PrintPanel(
const PanelSpec &inPanel,
RgnHandle inSuperPrintRgnH)
{
// Don't print if invisible
if (IsVisible()) {
// Area of this View to print is the
// intersection of inSuperPrintRgnH
// with the Revealed area of this View
RectRgn(mUpdateRgnH, &mRevealedRect);
if (inSuperPrintRgnH != nil) {
SectRgn(inSuperPrintRgnH, mUpdateRgnH, mUpdateRgnH);
}
if ( !EmptyRgn(mUpdateRgnH) &&
ScrollToPanel(inPanel) &&
FocusDraw()) {
// Some portion needs to be printed
PrintPanelSelf(inPanel);
// Let SubPanes print within this
// Panel of its SuperView
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->SuperPrintPanel(inPanel, mUpdateRgnH);
}
}
SetEmptyRgn(mUpdateRgnH); // Emptying update region frees up memory
// if this region wasn't rectangular
}
}
// ---------------------------------------------------------------------------
// • SuperPrintPanel
// ---------------------------------------------------------------------------
// SuperView is printing a panel
//
// The View is not in control of pagination. In general, it is not clear
// how to print nested scrolling views. This function just prints the
// View at its current location, without scrolling to a particular panel.
void
LView::SuperPrintPanel(
const PanelSpec &inSuperPanel,
RgnHandle inSuperPrintRgnH)
{
// Don't print if invisible
if (IsVisible()) {
// Area of this View to print is the
// intersection of inSuperPrintRgnH
// with the Revealed area of this View
RectRgn(mUpdateRgnH, &mRevealedRect);
if (inSuperPrintRgnH != nil) {
SectRgn(inSuperPrintRgnH, mUpdateRgnH, mUpdateRgnH);
}
if ( !EmptyRgn(mUpdateRgnH) && FocusDraw()) {
// Some portion needs to be printed
PrintPanelSelf(inSuperPanel);
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->SuperPrintPanel(inSuperPanel, mUpdateRgnH);
}
}
SetEmptyRgn(mUpdateRgnH); // Emptying update region frees up memory
// if this region wasn't rectangular
}
}
// ---------------------------------------------------------------------------
// • ScrollToPanel
// ---------------------------------------------------------------------------
// Scroll View Image to the specified Panel
//
// Return whether the specified Panel exists. If it doesn't, View is
// not scrolled.
Boolean
LView::ScrollToPanel(
const PanelSpec &inPanel)
{
Boolean panelInImage = false;
SDimension16 frameSize;
GetFrameSize(frameSize);
Uint32 horizPanelCount;
Uint32 vertPanelCount;
CountPanels(horizPanelCount, vertPanelCount);
if ((inPanel.horizIndex <= horizPanelCount) &&
(inPanel.vertIndex <= vertPanelCount)) {
Int32 horizPos = frameSize.width * (inPanel.horizIndex - 1);
Int32 vertPos = frameSize.height * (inPanel.vertIndex - 1);
ScrollImageTo(horizPos, vertPos, false);
panelInImage = true;
}
return panelInImage;
}
void
LView::ScrollImageTo(
Int32 inLeftLocation,
Int32 inTopLocation,
Boolean inRefresh)
{
ScrollImageBy(mImageLocation.h - mFrameLocation.h + inLeftLocation,
mImageLocation.v - mFrameLocation.v + inTopLocation,
inRefresh);
}
// ---------------------------------------------------------------------------
// • ScrollImageBy
// ---------------------------------------------------------------------------
// Scroll Image by specified horizontal and vertical increments
//
// Scrolling moves the Image relative to the Frame and Port, so that a
// different portion of the Image is visible thru the Frame.
//
// Positive deltas scroll right and down.
// Negative deltas scroll left and up.
//
// If inRefresh is true, the Port containing the View is updated
// immediately, rather than refreshed at the next update event.
// Scrolling usually happens during mouse down tracking, so we want
// immediate visual feedback.
void
LView::ScrollImageBy(
Int32 inLeftDelta, // Pixels to scroll horizontally
Int32 inTopDelta, // Pixels to scroll vertically
Boolean inRefresh)
{
if (inRefresh) {
// Check if any portion of what is visible now will be
// visible after the scroll. If so, it should be faster
// to move the bits rather than redrawing them.
Int32 absLeftDelta = inLeftDelta;
if (absLeftDelta < 0) {
absLeftDelta = -absLeftDelta;
}
Int32 absTopDelta = inTopDelta;
if (absTopDelta < 0) {
absTopDelta = -absTopDelta;
}
if ( (absLeftDelta < (mRevealedRect.right - mRevealedRect.left)) &&
(absTopDelta < (mRevealedRect.bottom - mRevealedRect.top)) ) {
ScrollBits(inLeftDelta, inTopDelta);
} else {
Refresh();
}
}
mImageLocation.h -= inLeftDelta; // Move Image
mImageLocation.v -= inTopDelta;
CalcPortOrigin();
OutOfFocus(this);
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
theSub->AdaptToSuperScroll(inLeftDelta, inTopDelta);
}
if (mSuperView != nil) {
mSuperView->SubImageChanged(this);
}
if (inRefresh) {
UpdatePort();
}
}
void
LView::ScrollBits(
Int32 inLeftDelta, // Pixels to scroll horizontally
Int32 inTopDelta) // Pixels to scroll vertically
{
if (FocusDraw()) {
Rect frame = mRevealedRect;
PortToLocalPoint(topLeft(frame));
PortToLocalPoint(botRight(frame));
RgnHandle updateRgnH = NewRgn();
ScrollRect(&frame, -inLeftDelta, -inTopDelta, updateRgnH);
InvalRgn(updateRgnH); // ??? Use InvalPaneRgn, but
// have to offset updateRgnH to
// Port coords.
DisposeRgn(updateRgnH);
}
}
Boolean
LView::AutoScrollImage(
Point inLocalPt)
{
Boolean scrolled = false;
Rect frame;
CalcLocalFrameRect(frame);
Int32 horizScroll = 0;
if (inLocalPt.h < frame.left) {
// AutoScroll left
Int32 leftMax = mFrameLocation.h - mImageLocation.h;
if (leftMax > 0) {
horizScroll = -mScrollUnit.h;
if (leftMax < mScrollUnit.h) {
horizScroll = -leftMax;
}
}
} else if (inLocalPt.h > frame.right) {
// AutoScroll right
Int32 rightMax = mImageSize.width - mFrameSize.width -
(mFrameLocation.h - mImageLocation.h);
if (rightMax > 0) {
horizScroll = mScrollUnit.h;
if (rightMax < horizScroll) {
horizScroll = rightMax;
}
}
}
Int32 vertScroll = 0;
if (inLocalPt.v < frame.top) {
// AutoScroll up
Int32 upMax = mFrameLocation.v - mImageLocation.v;
if (upMax > 0) {
vertScroll = -mScrollUnit.v;
if (upMax < mScrollUnit.v) {
vertScroll = -upMax;
}
}
} else if (inLocalPt.v > frame.bottom) {
// AutoScroll down
Int32 downMax = mImageSize.height - mFrameSize.height -
(mFrameLocation.v - mImageLocation.v);
if (downMax > 0) {
vertScroll = mScrollUnit.v;
if (downMax < vertScroll) {
vertScroll = downMax;
}
}
}
if ((horizScroll != 0) || (vertScroll != 0)) {
ScrollImageBy(horizScroll, vertScroll, true);
scrolled = true;
}
return scrolled;
}
void
LView::ResizeImageTo(
Int32 inWidth,
Int32 inHeight,
Boolean inRefresh)
{
ResizeImageBy(inWidth - mImageSize.width,
inHeight - mImageSize.height,
inRefresh);
}
void
LView::ResizeImageBy(
Int32 inWidthDelta,
Int32 inHeightDelta,
Boolean inRefresh)
{
mImageSize.width += inWidthDelta;
mImageSize.height += inHeightDelta;
ReconcileFrameAndImage(inRefresh);
if (mSuperView != nil) {
mSuperView->SubImageChanged(this);
}
}
// ---------------------------------------------------------------------------
// • ReconcileFrameAndImage
// ---------------------------------------------------------------------------
// Adjusts the Image so that it fits within the Frame
//
// This function addresses the problem of what to do when you scroll a
// View to at or near the bottom or right, then make the View's Frame
// larger. This would normally expose some "undefined" area below or
// to the right of the Image.
//
// If mReconcileOverhang is true, this function scrolls the Image so that
// the bottom right corner is at the bottom right of the Frame. However,
// it never moves the top left corner of the Image beyond the top left
// of the Frame. Therefore, the only time "undefined" area is exposed is
// when the Frame is larger than the Image.
//
// For Views with fixed Image sizes, such as drawings where the Image size
// is the size of a printed page, set mReconcileOverhang to true. The user
// does not normally want to see past the bottom or right of such Views.
//
// For Views with variable Image sizes, such as text blocks where the size
// of the Image depends on the number of lines of text, set
// mReconcileOverhang to false. The user may want to see the undefined
// area in anticipation of the Image growing.
void
LView::ReconcileFrameAndImage(
Boolean inRefresh)
{
if (mReconcileOverhang) {
SPoint32 currScrollPos;
GetScrollPosition(currScrollPos);
SPoint32 newScrollPos = currScrollPos;
// Reconcile Vertical position
if ( (mFrameLocation.v + mFrameSize.height) >
(mImageLocation.v + mImageSize.height) ) {
// Frame extends below Image
newScrollPos.v = mImageSize.height - mFrameSize.height;
if (newScrollPos.v < 0) {
newScrollPos.v = 0;
}
// Force newScrollPos to be a multiple
// of mScrollUnit
newScrollPos.v = mScrollUnit.v *
((newScrollPos.v + mScrollUnit.v - 1) / mScrollUnit.v);
}
// Reconcile horizontal position
if ( (mFrameLocation.h + mFrameSize.width) >
(mImageLocation.h + mImageSize.width) ) {
// Frame extends right Image
newScrollPos.h = mImageSize.width - mFrameSize.width;
if (newScrollPos.h < 0) {
newScrollPos.h = 0;
}
// Force newScrollPos to be a multiple
// of mScrollUnit
newScrollPos.h = mScrollUnit.h *
((newScrollPos.h + mScrollUnit.h - 1) / mScrollUnit.h);
}
if ( (newScrollPos.v != currScrollPos.v) ||
(newScrollPos.h != currScrollPos.h) ) {
ScrollImageTo(newScrollPos.h, newScrollPos.v, inRefresh);
}
}
}
void
LView::SetScrollUnit(
const SPoint32 &inScrollUnit)
{
mScrollUnit = inScrollUnit;
if (mSuperView != nil) {
mSuperView->SubImageChanged(this);
}
}
void
LView::GetScrollUnit(
SPoint32 &outScrollUnit) const
{
outScrollUnit = mScrollUnit;
}
void
LView::SubImageChanged(
LView *inSubView)
{
}
// ---------------------------------------------------------------------------
// • FindSubPaneHitBy
// ---------------------------------------------------------------------------
// Find the SubPane of this View that is hit by the specified point.
// Return nil if no SubPane is hit
//
// inHorizPort and inVertPort are in Port coordinates
LPane*
LView::FindSubPaneHitBy(
Int32 inHorizPort,
Int32 inVertPort)
{
LPane *hitSubPane = nil;
LListIterator iterator(mSubPanes, iterate_FromEnd);
LPane *subPane;
while (iterator.Previous(subPane)) {
if (subPane->IsHitBy(inHorizPort, inVertPort)) {
hitSubPane = subPane;
break;
}
}
return hitSubPane;
}
// ---------------------------------------------------------------------------
// • Click
// ---------------------------------------------------------------------------
// Handle a click inside a View
void
LView::Click(
SMouseDownEvent &inMouseDown)
{
// Check if a SubPane of this View
// is hit
LPane *clickedPane = FindSubPaneHitBy(inMouseDown.wherePort.h,
inMouseDown.wherePort.v);
if (clickedPane != nil) { // SubPane is hit, let it respond to
// the Click
clickedPane->Click(inMouseDown);
} else { // No SubPane hit. Inherited function
LPane::Click(inMouseDown); // will process click on this View
}
}
void
LView::AdjustCursor(
Point inPortPt,
const EventRecord &inMacEvent)
{
// Check if a SubPane of this View
// contains the point
LPane *hitPane = FindSubPaneHitBy(inPortPt.h, inPortPt.v);
if (hitPane != nil) { // SubPane is hit, let it adjust the
// cursor shape
hitPane->AdjustCursor(inPortPt, inMacEvent);
} else { // No SubPane hit. This View adjusts
// the cursor.
AdjustCursorSelf(inPortPt, inMacEvent);
}
}
// ---------------------------------------------------------------------------
// • FindPaneByID
// ---------------------------------------------------------------------------
// Find the Pane of a View which has the specified ID
//
// Searches all Panes contained within this View, not just direct
// subpanes. Returns nil if Pane with the target ID is not found.
//
LPane*
LView::FindPaneByID(
PaneIDT inPaneID)
{
LPane *thePane = nil;
if (inPaneID == mPaneID) { // Check first if this is the one
thePane = this;
} else {
// Search all subpanes
LListIterator iterator(mSubPanes, iterate_FromStart);
LPane *theSub;
while (iterator.Next(theSub)) {
thePane = theSub->FindPaneByID(inPaneID);
if (thePane != nil) break;
}
}
return thePane;
}
Int32
LView::GetValueForPaneID(
PaneIDT inPaneID) const
{
Int32 value = 0;
LPane *thePane = FindPaneByID(inPaneID);
if (thePane != nil) {
value = thePane->GetValue();
} else {
BreakIfDebug_("GetValue For Unknown Pane ID");
}
return value;
}
void
LView::SetValueForPaneID(
PaneIDT inPaneID,
Int32 inValue)
{
LPane *thePane = FindPaneByID(inPaneID);
if (thePane != nil) {
thePane->SetValue(inValue);
} else {
BreakIfDebug_("SetValue for Unknown Pane ID");
}
}
StringPtr
LView::GetDescriptorForPaneID(
PaneIDT inPaneID,
Str255 outDescriptor) const
{
LPane *thePane = FindPaneByID(inPaneID);
if (thePane != nil) {
thePane->GetDescriptor(outDescriptor);
} else {
BreakIfDebug_("GetValue for Unknown Pane ID");
}
return outDescriptor;
}
void
LView::SetDescriptorForPaneID(
PaneIDT inPaneID,
ConstStr255Param inDescriptor)
{
LPane *thePane = FindPaneByID(inPaneID);
if (thePane != nil) {
thePane->SetDescriptor(inDescriptor);
} else {
BreakIfDebug_("SetValue for Unknown Pane ID");
}
}
// ---------------------------------------------------------------------------
// • PortToLocalPoint
// ---------------------------------------------------------------------------
// Convert point from Port to Local coordinates
void
LView::PortToLocalPoint(
Point &ioPoint) const
{
ioPoint.h += mPortOrigin.h;
ioPoint.v += mPortOrigin.v;
}
// ---------------------------------------------------------------------------
// • LocalToPortPoint
// ---------------------------------------------------------------------------
// Convert point from Local to Port coordinates
void
LView::LocalToPortPoint(
Point &ioPoint) const
{
ioPoint.h -= mPortOrigin.h;
ioPoint.v -= mPortOrigin.v;
}
// ---------------------------------------------------------------------------
// • ImageToLocalPoint
// ---------------------------------------------------------------------------
// Convert point from Image (32-bit) to Local (16-bit) coordinates
//
// Image and Local coordinates are different only when the Image size
// is greater than 16K (15-bit)
void
LView::ImageToLocalPoint(
const SPoint32 &inImagePt,
Point &outLocalPt)
{
outLocalPt.h = inImagePt.h + mPortOrigin.h + mImageLocation.h;
outLocalPt.v = inImagePt.v + mPortOrigin.v + mImageLocation.v;
}
// ---------------------------------------------------------------------------
// • LocalToImagePoint
// ---------------------------------------------------------------------------
// Convert point from Local (16-bit) to Image (32-bit) coordinates
//
// Image and Local coordinates are different only when the Image size
// is greater than 16K (15-bit)
void
LView::LocalToImagePoint(
const Point &inLocalPt,
SPoint32 &outImagePt)
{
outImagePt.h = inLocalPt.h - mPortOrigin.h - mImageLocation.h;
outImagePt.v = inLocalPt.v - mPortOrigin.v - mImageLocation.v;
}